iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
0
Software Development

用Canvas打造自己的遊樂場系列 第 15

[Day15]用Canvas打造自己的遊樂場-Galaxian 射擊

  • 分享至 

  • xImage
  •  

原本今天我想做的部分是,畫出很瞎趴玩家角色還有敵人,但我馬上明白自己的藝術天份堪稱悲劇,不過這也是不影響整個遊戲啦,我們就以圓圈來代替各種角色吧, 哈哈哈
今天的進度呢就定在完成玩家這角色能正常的射擊,先畫出玩家的角色,這邊呢附上會需要做修改的地方,不過因為還沒有出現第一個遊戲以外的新程式,所以就不多加說明啦。

 // 玩家設定
const PLAYER_DIST_FROM_EDGE = 50; 
const PLAYER_R = 15;
var player_x = 400;
// 游標位置
mousePos = (event) => {
    var rect = canvas.getBoundingClientRect();
    var root = document.documentElement;

    var mouse_x = event.clientX - rect.left - root.scrollLeft;

    // 玩家X軸座標
    player_x = mouse_x;
}
// 負責畫畫
draw = () => {
    // background
    drawRectangle(0, 0, canvas.width, canvas.height, 'black');

    // 畫線
    drawLine(0, LIFE_SIZE, canvas.width, LIFE_SIZE, 'white')

    // 畫出生命
    showLife(chance);

    // 畫出玩家
    drawCircle(player_x, (canvas.height - PLAYER_DIST_FROM_EDGE), PLAYER_R, 'gray')

}

到這邊應該都還算順利吧? 到了這應該可以正常的顯示代表玩家的圓,圓也可以根據滑鼠位置來操控.

接下來先來新增一下子彈的設定

// 玩家子彈設定
const BULLET_R = 2.5;
const BULLET_SPEED = 20;
var bullet_x;
var bullet_y;
var player_shot = false;

這邊的player_shot代表的意義是,玩家是否發射子彈. 遊戲中預設玩家一次只能有一發子彈在場上,當然這可以隨大家喜好修改,只是後面判斷是也要做個小修改.

然後呢,就是寫顯示子彈的函式,然後將他加入顯示畫面的函式中.

// 顯示子彈
showBullet = () => {
    // 如果玩家發射子彈
    if(player_shot) {
        drawCircle(bullet_x, bullet_y, BULLET_R, '#FF9D6F')
    }
}
 // 負責畫畫
draw = () => {
    // background
    drawRectangle(0, 0, canvas.width, canvas.height, 'black');

    // 畫線
    drawLine(0, LIFE_SIZE, canvas.width, LIFE_SIZE, 'white')

    // 畫出生命
    showLife(chance);

    // 畫出玩家
    drawCircle(player_x, (canvas.height - PLAYER_DIST_FROM_EDGE), PLAYER_R, 'gray')

    // 顯示子彈
    showBullet();

}

這邊已經可以顯示子彈畫面上了,只是因為我們的子彈目前都是處於未擊發的狀態,所以看不到.
馬上來新增擊發的方式.

window.onload = () => {
    canvas = document.getElementById('playground');
    canvasContext = canvas.getContext('2d');

    //一秒更新幾次畫面
    var timesPerSec = 30;
    setInterval(drawAll, 1000 / timesPerSec);

    // 抓滑鼠位置
    canvas.addEventListener('mousemove', mousePos);

    // 滑鼠點擊
    canvas.addEventListener('mousedown', mouseClick);
}


// 滑鼠點擊
mouseClick = (event) => {
    playerShoot();
}

這邊代表著當滑鼠點擊後,會觸發mouseClick的函式.點擊後的觸發如下

// 玩家發射子彈
playerShoot = () => {
    if(player_shot == false) {
        bullet_x = player_x;
        bullet_y = (canvas.height - PLAYER_DIST_FROM_EDGE - PLAYER_R);
        player_shot = true;
    }
}

到這邊,子彈已經會顯示了出來了,不過呢,還不會移動.
要再增加個子彈移動的函式,並且在子彈超出畫面時,重新上膛.

// 負責處理動作
move = () => {

    // 子彈移動
    moveBullet();
}

// 移動子彈
moveBullet = () => {
    // 玩家發射子彈
    if(player_shot) {
        bullet_y -= BULLET_SPEED;

        // 若子彈超出邊界,重新上膛
        if(bullet_y < 0) {
            player_shot = false;
        }
    }
}

OK! 到這裡,已經可以正常發射子彈了.
明天,來完成敵人會自動左右移動吧.

在這邊先附上到這邊為止的程式碼

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Second Game</title>
    <meta name="description" content="第一個遊戲">
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
</head>

<body>
    <canvas id="playground" width="800" height="630"></canvas>
    <script>

        // 生命設定
        const LIFE_SIZE = 30;
        var chance = 3;

        // 玩家設定
        const PLAYER_DIST_FROM_EDGE = 50; 
        const PLAYER_R = 15;
        var player_x = 400;

        // 玩家子彈設定
        const BULLET_R = 2.5;
        const BULLET_SPEED = 20;
        var bullet_x;
        var bullet_y;
        var player_shot = false;

        
        window.onload = () => {
            canvas = document.getElementById('playground');
            canvasContext = canvas.getContext('2d');

            //一秒更新幾次畫面
            var timesPerSec = 30;
            setInterval(drawAll, 1000 / timesPerSec);

            // 抓滑鼠位置
            canvas.addEventListener('mousemove', mousePos);

            // 滑鼠點擊
            canvas.addEventListener('mousedown', mouseClick);
        }

        // 負責更新畫面
        drawAll = () => {
            move();
            draw();
        }

        // 負責畫畫
        draw = () => {
            // background
            drawRectangle(0, 0, canvas.width, canvas.height, 'black');

            // 畫線
            drawLine(0, LIFE_SIZE, canvas.width, LIFE_SIZE, 'white')

            // 畫出生命
            showLife(chance);

            // 畫出玩家
            drawCircle(player_x, (canvas.height - PLAYER_DIST_FROM_EDGE), PLAYER_R, 'gray')

            // 顯示子彈
            showBullet();

        }

        // 負責處理動作
        move = () => {
            
            // 子彈移動
            moveBullet();
        }
        
        // 顯示子彈
        showBullet = () => {
            // 如果玩家發射子彈
            if(player_shot) {
                drawCircle(bullet_x, bullet_y, BULLET_R, '#FF9D6F')
            }
        }

        // 玩家發射子彈
        playerShoot = () => {
            if(player_shot == false) {
                bullet_x = player_x;
                bullet_y = (canvas.height - PLAYER_DIST_FROM_EDGE - PLAYER_R);
                player_shot = true;
            }
        }

        // 移動子彈
        moveBullet = () => {
            // 玩家發射子彈
            if(player_shot) {
                bullet_y -= BULLET_SPEED;
                
                // 若子彈超出邊界,重新上膛
                if(bullet_y < 0) {
                    player_shot = false;
                }
            }
        }

        // 矩形元件
        drawRectangle = (topLeftX, topLeftY, boxWidth, boxHeight, color) => {
            canvasContext.fillStyle = color;
            canvasContext.fillRect(topLeftX, topLeftY, boxWidth, boxHeight);
        }

        // 圓形元件
        drawCircle = (centerX, centerY, r, color) => {
            canvasContext.fillStyle = color;
            canvasContext.beginPath();
            canvasContext.arc(centerX, centerY, r, 0, Math.PI * 2);
            canvasContext.fill();
        }

        // 畫線
        drawLine = (beginX, beginY, endX, endY, color) => {
            canvasContext.strokeStyle = color;
            canvasContext.beginPath();
            canvasContext.moveTo(beginX, beginY);
            canvasContext.lineTo(endX, endY);
            canvasContext.stroke();
        }

        // 畫生命
        drawLife = (lifeX, lifeY, size, color) => {
            canvasContext.fillStyle = color;
            canvasContext.beginPath();
            canvasContext.arc(lifeX + size / 4, lifeY + size / 4, size / 4, Math.PI * 1, Math.PI * 0);
            canvasContext.arc(lifeX + size * 3 / 4, lifeY + size / 4, size / 4, Math.PI * 1, Math.PI * 0);
            canvasContext.moveTo(lifeX + size, lifeY + size / 4);
            canvasContext.lineTo(lifeX + size / 2, lifeY + size);
            canvasContext.lineTo(lifeX, lifeY + size / 4);
            canvasContext.fill();
        }

        // 畫出生命
        showLife = (num) => {
            for (let life_count = 0; life_count < num; life_count++) {
                drawLife(LIFE_SIZE * life_count, 0, LIFE_SIZE, 'red');
            }
        }

        // 滑鼠點擊
        mouseClick = (event) => {
            playerShoot();
        }

        // 游標位置
        mousePos = (event) => {
            var rect = canvas.getBoundingClientRect();
            var root = document.documentElement;

            var mouse_x = event.clientX - rect.left - root.scrollLeft;

            // 玩家X軸座標
            player_x = mouse_x;
        }

    </script>
</body>

</html>

上一篇
[Day14]用Canvas打造自己的遊樂場-Galaxian 開工
下一篇
[Day16]用Canvas打造自己的遊樂場-Galaxian 中秋團圓
系列文
用Canvas打造自己的遊樂場30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言